﻿namespace MonetDbDataProvider.Mapi
{
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;

    using MonetDbDataProvider.Security;

    public static class MapiSocketFactory
    {
        private static int poolSize;

        private static List<DatabaseConnection> databaseConnections; 

        private static ICryptoProvider cryptoProvider;

        static MapiSocketFactory()
        {
            databaseConnections = new List<DatabaseConnection>();
            cryptoProvider = new CryptoProvider();
        }

        public static MapiSocket GetSocket(ConnectionString connectionString)
        {
            MapiSocket availableSocket = null;

            if (!databaseConnections.Any())
                databaseConnections.Add(GenerateDatabaseConnection(connectionString));

            var databaseConnection = databaseConnections.SingleOrDefault(c => c.ConnectionString.ToString() == connectionString.ToString());

            if (databaseConnection != null && databaseConnections != null)
            {
                if (databaseConnections != null && !databaseConnection.ConnectionPool.Any())
                    databaseConnection.ConnectionPool.Enqueue(GenerateMapiSocket(connectionString));

                lock (databaseConnections)
                    databaseConnection.ConnectionPool.TryDequeue(out availableSocket);                
            }

            return availableSocket;
        }

        public static void CloseSocket(ConnectionString connectionString, MapiSocket openSocket)
        {
            lock (databaseConnections)
            {
                var databaseConnection = databaseConnections.SingleOrDefault(c => c.ConnectionString == connectionString);

                if (databaseConnection != null)
                    databaseConnection.ConnectionPool.Enqueue(openSocket);
            }
        }

        private static DatabaseConnection GenerateDatabaseConnection(ConnectionString connectionString)
        {
            var pool = new ConcurrentQueue<MapiSocket>();
            pool.Enqueue(GenerateMapiSocket(connectionString));

            return new DatabaseConnection()
                       {
                           ConnectionString = connectionString,
                           ConnectionPool = pool
                       };
        }

        private static MapiSocket GenerateMapiSocket(ConnectionString connectionString)
        {
            var newSocket = new MapiSocket(cryptoProvider);
            newSocket.Connect(connectionString);

            return newSocket;
        }
    }
}
